package impl

import (
	"context"
	"fmt"
	"strings"
	"time"
	"vblog/apps/token"
	"vblog/apps/user"
	"vblog/common"
	"vblog/conf"
	"vblog/exception"
	"vblog/ioc"

	"gorm.io/gorm"
)

var _ token.Service = &TokenServiceImpl{}
var _ ioc.Object = &TokenServiceImpl{}

// var UserController = UserServiceImpl.ServiceImpl()
// var userServiceImpl user.Service

func init() {
	// userServiceImpl = ioc.Controller.Get(user.AppName).(user.Service)
	ioc.Controller.Registry(token.AppName, &TokenServiceImpl{})

}

type TokenServiceImpl struct {
	db          *gorm.DB
	userService user.Service
}

// func NewTokenServiceImpl() *TokenServiceImpl {
// 	return &TokenServiceImpl{
// 		db: *conf.C().MySQL.GetDB(),
// 	}
// }

func (i *TokenServiceImpl) TokenModel() *gorm.DB {
	return i.db.Model(&token.Token{})
}

func (i *TokenServiceImpl) Init() error {
	// 初始化db
	i.db = conf.C().MySQL.GetDB()
	// fmt.Println(ioc.Controller.Get(user.AppName).(user.Service))
	i.userService = ioc.Controller.Get(user.AppName).(user.Service)
	return nil
}

// 颁发
func (i *TokenServiceImpl) IssueToken(ctx context.Context, in *token.IssueTokenRequest) (*token.Token, error) {

	//  调用user.Query 验证用户名密码
	describeUser := user.NewDescribeUserRequest()
	describeUser.Username = in.Username

	user, err := i.userService.DescribeUser(ctx, describeUser)
	if err != nil {
		return nil, err
	}

	// 验证密码

	fmt.Println("DescribeUser", user)
	if err := common.VerifyPassword(user.Password, in.Password); err != nil {
		fmt.Printf("%v", exception.ErrorAuthFailed)

		return nil, exception.ErrorAuthFailed
	}

	// 生成token
	token := token.NewToken()
	if err = token.GenAccessToken(); err != nil {
		return nil, err
	}
	// Refresh Token
	_ = token.GenRefreshToken()

	token.UserId = user.Id
	token.Username = user.Username
	token.CreatedAt = time.Now().Unix()
	token.Role = user.Role

	// 判断token是否存在

	// 保存到数据库
	// INSERT INTO `tokens` (`created_at`,`updated_at`,`user_id`,`username`,`access_token`,`access_token_expired_at`,`refresh_token`,`refresh_token_expired_at`) VALUES (1717053026,1717053026,1,'admin02','DjLUEm7dK_4qGpkhGAs58j_lwCvzn8NH0LAk6tjA_Ok=',1717060226,'qxV0WXcBkN-j_wpf-IYUWT4wgHs2zB_HT6AOxAi4y7I=',1717067426)	err = i.TokenModel().WithContext(ctx).Create(token).Error
	err = i.TokenModel().WithContext(ctx).Create(token).Error
	if err != nil {
		return nil, exception.ErrorServerInternal("IssueToken 保存失败,%s", err)
	}

	return token, nil
}

// 撤销
func (i *TokenServiceImpl) RevolkToken(ctx context.Context, in *token.RevolkTokenRequest) (*token.Token, error) {
	in.AccessToken = strings.TrimSpace(in.AccessToken)
	if len(in.AccessToken) == 0 {
		return nil, exception.ErrorNotFound("AccessToken 不能为空")
	}
	in.RefreshToken = strings.TrimSpace(in.RefreshToken)
	if len(in.RefreshToken) == 0 {
		return nil, exception.ErrorNotFound("RefreshToken 不能为空")
	}

	tk := token.NewToken()
	err := i.TokenModel().
		WithContext(ctx).
		Where("access_token = ? and refresh_token = ?", in.AccessToken, in.RefreshToken).
		First(tk).
		Error

	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, exception.ErrorNotFound("RevolkToken 记录未找到")
		}

		return nil, exception.ErrorServerInternal("RevolkToken 内部错误,%s", err)
	}

	// return tk, nil
	err = i.TokenModel().
		WithContext(ctx).
		Where("access_token = ? and refresh_token = ?", in.AccessToken, in.RefreshToken).
		Delete(&tk).
		Error

	if err != nil {
		return nil, exception.ErrorServerInternal("RevolkToken 删除失败,%s", err)
	}

	return tk, nil
}

// 校验
func (i *TokenServiceImpl) ValidateToken(ctx context.Context, in *token.ValidateTokenRequest) (*token.Token, error) {
	// 查询token

	tk := token.NewToken()

	err := i.TokenModel().Where("access_token = ?", in.AccessToken).First(&tk).Error
	if err != nil {
		if err.Error() == gorm.ErrRecordNotFound.Error() {
			return nil, exception.ErrorNotFound("ValidateToken 记录未找到,%s", err)
		}
		return nil, err
	}

	// 通过username 查询用户的角色信息，并保存到token role中
	dUser := user.NewDescribeUserRequest()
	dUser.Username = tk.Username
	u, err := i.userService.DescribeUser(ctx, dUser)
	if err != nil {
		return nil, err
	}

	tk.Role = u.Role

	// 过期
	now := time.Now().Unix()
	if now > tk.AccessTokenExpiredAt && now > tk.RefreshTokenExpiredAt {
		// Token过期
		_, _ = i.RevolkToken(ctx, token.NewRevolkTokenRequest(tk.AccessToken, tk.RefreshToken))
		return nil, token.ErrorRefreshTokenExpired

	} else if now < tk.AccessTokenExpiredAt {
		// AccessToken未过期
		return tk, nil
	}

	// now > tk.AccessTokenExpiredAt && now < tk.RefreshTokenExpiredAt
	// AccessToken过期 RefreshToken未过期
	if err = tk.GenAccessToken(); err != nil {
		return nil, err
	}

	// 更新数据库
	err = i.TokenModel().WithContext(ctx).Where("user_id = ?", tk.UserId).Save(&tk).Error
	// err = i.TokenModel().WithContext(ctx).Where("user_id = ?", tk.UserId).Updates(&tk).Error
	if err != nil {
		return nil, exception.ErrorServerInternal("ValidateToken 保存失败,%s", err)
	}

	return tk, nil

}
